/***************************************************************************************** 
*                                     TinyRtos51 
*                                The Real-Time Kernel 
*                              Copyright(c) 2024 fanxsp
*                         SPDX-License-Identifier: APACHE-2.0
*       This software is subject to an open source license and is distributed by fanxsp,
*       pursuant to the terms of the Apache License.
******************************************************************************************/
/***************************************************************************************** 
* 				TinyRtos51 OSCoreAsm.c
* Author: fanxsp 
* Revision: 1.00
* Date: 2023-08-24
* 	有嵌入汇编的 C文件
* Revision: 1.10
* Date: 2024-04-07
*	增加reentrant函数支持
******************************************************************************************/
#define __IN_OSCORE_ASM_C
#include "tinyrtos51.h"

__data volatile unsigned char __at(0x00) ar0;
__data volatile unsigned char __at(0x01) ar1;
__data volatile unsigned char __at(0x02) ar2;
__data volatile unsigned char __at(0x03) ar3;
__data volatile unsigned char __at(0x04) ar4;
__data volatile unsigned char __at(0x05) ar5;
__data volatile unsigned char __at(0x06) ar6;
__data volatile unsigned char __at(0x07) ar7;

#if OSENABLE_REENTRANT_SMALL > 0
__asm
	EXTRN DATA  (?C_IBP)
__endasm
#endif

#if OSENABLE_REENTRANT_LARGE > 0
__asm
	EXTRN DATA  (?C_XBP)
	EXTRN DATA  (OSLargeStack)
	EXTRN DATA  (OSXBPSave)
__endasm
#endif

/* 启动OS  */
void OSStart(void) 
{
#if OSENABLE_REENTRANT_LARGE > 0
__asm
	MOV OSLargeStack, ?C_XBP
	MOV OSLargeStack+1, ?C_XBP+1
__endasm
#endif
	OSStack = SP ;
	OSTaskRunning = OSHiPrioInList(OSHeadEligible) ;
#if OSENABLE_REENTRANT_LARGE > 0
	OSTmp16u = (OStypeInt16u)OSTcbArea[OSTaskRunning].largeStackTop ;
__asm
	MOV ?C_XBP,OSTmp16u
	MOV ?C_XBP+1, OSTmp16u+1
__endasm
#endif

	ACC = OSTcbArea[OSTaskRunning].stackBottom[0];

	__asm__ ("push ACC");

	ACC = OSTcbArea[OSTaskRunning].stackBottom[1];

	__asm__ ("push ACC");

	OSEi() ;
}

/* 任务上下文切换  */
void OSCtxSw(void)
{
	OStypeInt8u OSLOC_STACKS *p ;
	OStypeInt8u i ;
	
	if(OSTaskRunning == OSTCBIDLE && OSTcbArea[OSTCBIDLE].pree == 1)  
	{
		SP -= 13 ; 
		OSTcbArea[OSTCBIDLE].pree = 0 ;
	}
	
//	SP++ ;
//	*(OStypeInt8u idata *)SP = OSEnterSum ;
	__asm__ ("PUSH _OSEnterSum");

	OSTcbArea[OSTaskRunning].stackSize = SP-OSStack ;
	p = OSTcbArea[OSTaskRunning].stackBottom + (OSTcbArea[OSTaskRunning].stackSize-1) ;
	while(SP > OSStack)
	{
//		*p = *(OStypeInt8u idata *)SP ;
//		SP-- ;
//		p-- ;
		__asm__ ("POP ACC");
		*p = ACC ;
		p-- ;
	}
	
	p = OSTcbArea[OSTaskNext].stackBottom ;
	for(i=OSTcbArea[OSTaskNext].stackSize;i!=0;i--)
	{
//		SP++ ;
//		*(OStypeInt8u idata *)SP = *p ;
//		p++ ;
		ACC = *p ;
		__asm__("PUSH ACC");
		p++ ;
	}
	
#if OSENABLE_REENTRANT_SMALL > 0
#pragma ASM
	MOV A, ?C_IBP
#pragma ENDASM
	i = ACC ;
	OSTcbArea[OSTaskRunning].smallStackSize = ~i+1 ;
	p = OSTcbArea[OSTaskRunning].smallStackBottom - (OSTcbArea[OSTaskRunning].smallStackSize-1) ;
	while(i)
	{
		*p = *(OStypeInt8u idata *)i ;
		i++ ; p++ ;
	}
	p = OSTcbArea[OSTaskNext].smallStackBottom ;
	for(i=0;i<OSTcbArea[OSTaskNext].smallStackSize;i++)
	{
		*(OStypeInt8u idata *)(0xff-i) = *(p-i) ;
	}
	ACC = ~i + 1 ;
#pragma ASM
	MOV ?C_IBP, ACC
#pragma ENDASM	
#endif

#if OSENABLE_REENTRANT_LARGE > 0
#pragma ASM
	MOV OSTmp16u, ?C_XBP
	MOV OSTmp16u+1, ?C_XBP+1
#pragma ENDASM
	OSTcbArea[OSTaskRunning].largeStackTop = (OStypeInt8u OSLOC_STACKS*)OSTmp16u ;
	OSTmp16u = (OStypeInt16u)OSTcbArea[OSTaskNext].largeStackTop ;
#pragma ASM
	MOV ?C_XBP, OSTmp16u
	MOV ?C_XBP+1, OSTmp16u+1
#pragma ENDASM	
#endif
	
	OSTaskRunning = OSTaskNext ;
//	OSEnterSum = *(OStypeInt8u idata*)SP ;
//	SP-- ;
	__asm__ ("PUSH _OSEnterSum");

	if(OSTcbArea[OSTaskNext].pree)
	{
		__asm__ ("POP ar7\n POP ar6\nPOP ar5\nPOP ar4\nPOP ar3\nPOP ar2\nPOP ar1\nPOP ar0\nPOP PSW\nPOP DPL\nPOP DPH\nPOP B\nPOP ACC");
	}
	OSEnterSum++ ;
	if(!(--OSEnterSum)) OSEi() ;
}

/* 任务级任务切换 不含进/出临界区 不能在用户程序中直接调用 */
void OSTaskSw(void) 
{
	OSTaskNext = OSHiPrioInList(OSHeadEligible) ;
	if(OSTaskNext != OSTaskRunning)
	{
		OSTcbArea[OSTaskRunning].pree = 0 ; 
//		SP++ ;
//		*(OStypeInt8u idata *)SP = (OStypeInt16u)OSCtxSw ;
//		SP++ ;
//		*(OStypeInt8u idata *)SP = (OStypeInt16u)OSCtxSw>>8 ;
// #pragma ASM
// //			MOV A,#LOW (OSCtxSw)
// //			PUSH ACC
// //			MOV A,#HIGH (OSCtxSw)
// //			PUSH ACC
// 			LJMP OSCtxSw
// #pragma ENDASM
		__asm__ ("LJMP _OSCtxSw");
	}
}

/* 中断级任务切换 在模拟PendSV的中断中调用 */
#if OSMETHOD > 0
void OSIntTaskSw(void) 
{
	OSDi() ;
	OSTaskNext=OSHiPrioInList(OSHeadEligible) ;
	if(OSTaskRunning != OSTaskNext)
	{
		OSTcbArea[OSTaskRunning].pree = 1 ; 
//		SP-- ;
//		*(OStypeInt8u idata *)SP = (OStypeInt16u)OSCtxSw ;
//		SP++ ;
//		*(OStypeInt8u idata *)SP = (OStypeInt16u)OSCtxSw>>8 ;
		__asm__ ("DEC SP\nDEC SP \nMOV A,#(_OSCtxSw)\nPUSH ACC\nMOV A,#(_OSCtxSw>>8)\nPUSH ACC\nRETI");
		
	}
	OSEi() ;
}
#endif

/* 中断嵌套跟踪 切换large reentrant 栈 */
#if OSENABLE_REENTRANT_LARGE > 0
void OSEnterInt(void)
{
	if(OSNesting == 0)
	{
		__asm
		MOV OSXBPSave, ?C_XBP
		MOV OSXBPSave+1, ?C_XBP+1
		MOV ?C_XBP, OSLargeStack
		MOV ?C_XBP+1, OSLargeStack+1
		__endasm
	}
	OSNesting ++ ;
	OSEi() ;
}

void OSExitInt(void)
{
	OSDi() ;
	if(!(--OSNesting))
	{
		__asm
		MOV ?C_XBP, OSXBPSave
		MOV ?C_XBP+1, OSXBPSave+1
		__endasm
	}
	OSEi() ;
}
#endif
